/*
 * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.haoc.lostandfound.fragment;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.haoc.lostandfound.activity.EditActivity;
import com.haoc.lostandfound.activity.MainActivity;
import com.haoc.lostandfound.R;
import com.haoc.lostandfound.clouddb.ThingEditFields;
import com.haoc.lostandfound.clouddb.CloudDBZoneWrapper;
import com.haoc.lostandfound.model.ThingInfo;
import com.haoc.lostandfound.utils.DateUtils;
import com.huawei.agconnect.cloud.database.CloudDBZoneQuery;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class HomePageFragment extends Fragment implements CloudDBZoneWrapper.UiCallBack {
    // 单击搜索菜单的请求码
    private static final int REQUEST_SEARCH = 1;

    // 单击添加菜单的请求码
    private static final int REQUEST_ADD = 2;

    // 保存当前排序的顺序
    private final SortState mSortState = new SortState();

    private final QueryInfo mQueryInfo = new QueryInfo();

    private final CloudDBZoneWrapper mCloudDBZoneWrapper;

    private Handler mHandler = null;

    private ThingInfoAdapter mThingInfoAdapter;

    private View mHeaderView;

    private View mBottomPanelView;

    private Menu mOptionMenu;

    private boolean mInSearchMode = false;

    private MainActivity mActivity;

    public HomePageFragment() {
        mCloudDBZoneWrapper = new CloudDBZoneWrapper();
    }

    public static Fragment newInstance() {
        return new HomePageFragment();
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        mActivity = (MainActivity) getActivity();
        mHandler = new Handler(Looper.getMainLooper());
        mThingInfoAdapter = new ThingInfoAdapter(getContext());
        mHandler.postDelayed(() -> {
            mCloudDBZoneWrapper.addCallBacks(HomePageFragment.this);
            mCloudDBZoneWrapper.createObjectType();
            mCloudDBZoneWrapper.openCloudDBZoneV2();
        }, 500);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_home, container, false);
        initThingListHeaderViews(rootView);
        initThingListView(rootView);
        initBottomPanelView(rootView);
        return rootView;
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
        mOptionMenu = menu;
        inflater.inflate(R.menu.thing_manager_menu, menu);
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        Intent intent = new Intent();
        if (getContext() != null) {
            intent.setClass(getContext(), EditActivity.class);
        }

        int id = item.getItemId();
        if (id == R.id.search_button) {
            intent.setAction(EditActivity.ACTION_SEARCH);
            startActivityForResult(intent, REQUEST_SEARCH);
        } else if (id == R.id.add_button) {
            intent.putExtra(ThingEditFields.EDIT_MODE, ThingEditFields.EditMode.ADD.name());
            intent.setAction(EditActivity.ACTION_ADD);
            startActivityForResult(intent, REQUEST_ADD);
        } else if (id == R.id.select_all) {
            mThingInfoAdapter.onSelectAllMenuClicked();
            updateSelectAllMenuHint(item);
        } else if (id == R.id.show_all) {
            restoreQueryState();
            mHandler.post(mCloudDBZoneWrapper::queryAllThings);
            toggleShowAllState(false);
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_CANCELED) {
            return;
        }
        restoreQueryState();
        if (requestCode == REQUEST_ADD) {
            processAddAction(data);
        } else {
            processSearchAction(data);
        }
    }

    private void restoreQueryState() {
        mQueryInfo.clean();
        cleanSortState();
    }

    //搜索
    private void processSearchAction(Intent data) {
        CloudDBZoneQuery<ThingInfo> query = CloudDBZoneQuery.where(ThingInfo.class);
        String thingName = data.getStringExtra(ThingEditFields.Thing_NAME);
        if (!TextUtils.isEmpty(thingName)) {
            // 查询thingName包含特定字符的结果
            query.contains(ThingEditFields.Thing_NAME, thingName);
            mQueryInfo.thingName = thingName;
        }

        int showCount = data.getIntExtra(ThingEditFields.SHOW_COUNT, 0);
        if (showCount > 0) {
            query.limit(showCount);
            mQueryInfo.showCount = showCount;
        }

        toggleShowAllState(true);
        mHandler.post(() -> mCloudDBZoneWrapper.queryThings(query));
    }

    //新增
    private void processAddAction(Intent data) {
        ThingInfo ThingInfo = new ThingInfo();
        int thingID = data.getIntExtra(ThingEditFields.Thing_ID, -1);
        if (thingID == -1) {
            ThingInfo.setId(mCloudDBZoneWrapper.getThingIndex() + 1);
        } else {
            ThingInfo.setId(thingID);
        }
        ThingInfo.setThingName(data.getStringExtra(ThingEditFields.Thing_NAME));
        ThingInfo.setLocation(data.getStringExtra(ThingEditFields.LOCATION));
        ThingInfo.setPhone(data.getStringExtra(ThingEditFields.PHONE));
        String dateTime = data.getStringExtra(ThingEditFields.Time);
        ThingInfo.setTime(DateUtils.parseDate(dateTime));
        toggleShowAllState(false);
        mHandler.post(() -> mCloudDBZoneWrapper.upsertThingInfos(ThingInfo));
    }

    @Override
    public void onDestroy() {
        mHandler.post(mCloudDBZoneWrapper::closeCloudDBZone);
        super.onDestroy();
    }

    //初始化顶部布局
    private void initThingListHeaderViews(View rootView) {
        // mHeaderView = inflater.inflate(R.layout.thing_manager_header, null);
        mHeaderView = rootView.findViewById(R.id.table_header);

        View thingNameHeaderView = mHeaderView.findViewById(R.id.header_thing_name);
        TextView thingNameTitleView = thingNameHeaderView.findViewById(R.id.title_name);
        thingNameTitleView.setText(R.string.thing_name);
        thingNameTitleView.setOnClickListener(v -> {
            updateSortState(ThingEditFields.Thing_NAME, thingNameHeaderView);
            queryWithOrder();
        });

        View timeHeaderView = mHeaderView.findViewById(R.id.header_time);
        TextView authorTitleView = timeHeaderView.findViewById(R.id.title_name);
        authorTitleView.setText(R.string.time);
        timeHeaderView.setOnClickListener(v -> {
            updateSortState(ThingEditFields.Time, timeHeaderView);
            queryWithOrder();
        });

        View locationHeaderView = mHeaderView.findViewById(R.id.header_location);
        TextView priceTitleView = locationHeaderView.findViewById(R.id.title_name);
        priceTitleView.setText(R.string.location);
        locationHeaderView.setOnClickListener(v -> {
            updateSortState(ThingEditFields.LOCATION, locationHeaderView);
            queryWithOrder();
        });

        View phoneHeaderView = mHeaderView.findViewById(R.id.header_phone);
        TextView publisherTitleView = phoneHeaderView.findViewById(R.id.title_name);
        publisherTitleView.setText(R.string.phone);
        phoneHeaderView.setOnClickListener(v -> {
            updateSortState(ThingEditFields.PHONE, phoneHeaderView);
            queryWithOrder();
        });
    }

    //初始化失物列表
    private void initThingListView(View rootView) {
        ListView thingListView = rootView.findViewById(R.id.thing_list);
        thingListView.setAdapter(mThingInfoAdapter);
        thingListView.setOnItemClickListener((parent, view, position, id) -> {
            if (mThingInfoAdapter.isMultipleMode()) {
                mThingInfoAdapter.check(position);
                updateSelectAllMenuHint(mOptionMenu.findItem(R.id.select_all));
            } else {
                //跳转到修改失物信息页面
                ThingInfo ThingInfo = (ThingInfo) mThingInfoAdapter.getItem(position);
                Intent intent = new Intent();
                if (getContext() != null) {
                    intent.setClass(getContext(), EditActivity.class);
                }
                intent.putExtra(ThingEditFields.Thing_ID, ThingInfo.getId());
                intent.putExtra(ThingEditFields.Thing_NAME, ThingInfo.getThingName());
                intent.putExtra(ThingEditFields.LOCATION, ThingInfo.getLocation());
                intent.putExtra(ThingEditFields.PHONE, ThingInfo.getPhone());
                intent.putExtra(ThingEditFields.Time, DateUtils.formatDate(ThingInfo.getTime()));
                intent.putExtra(ThingEditFields.EDIT_MODE, ThingEditFields.EditMode.MODIFY.name());
                intent.setAction(EditActivity.ACTION_ADD);
                startActivityForResult(intent, REQUEST_ADD);
            }
        });
        //长按多选事件
        thingListView.setOnItemLongClickListener((parent, view, position, id) -> {
            if (!mThingInfoAdapter.isMultipleMode()) {
                mThingInfoAdapter.setMultipleMode(true);
                invalidateViewInMultipleChoiceMode();
            }
            return false;
        });
    }

    @Override
    public void onPrepareOptionsMenu(@NonNull Menu menu) {
        super.onPrepareOptionsMenu(menu);
        if (mThingInfoAdapter.isMultipleMode()) {
            invalidateViewInMultipleChoiceMode();
        } else {
            invalidateViewInNormalMode();
        }
    }

    private void initBottomPanelView(View rootView) {
        mBottomPanelView = rootView.findViewById(R.id.buttonPanel);
        Button deleteButton = mBottomPanelView.findViewById(R.id.delete);
        deleteButton.setOnClickListener(v -> {
            List<ThingInfo> ThingInfoList = mThingInfoAdapter.getSelectedItems();
            mHandler.post(() -> mCloudDBZoneWrapper.deleteThingInfos(ThingInfoList));
            invalidateViewInNormalMode();
        });
        Button cancelButton = mBottomPanelView.findViewById(R.id.cancel);
        cancelButton.setOnClickListener(v -> invalidateViewInNormalMode());
    }

    // 多选模式
    private void invalidateViewInMultipleChoiceMode() {
        mHeaderView.findViewById(R.id.checkbox).setVisibility(View.INVISIBLE);
        mBottomPanelView.setVisibility(View.VISIBLE);
        mActivity.hideNavigationBar();

        int menuSize = mOptionMenu.size();
        for (int i = 0; i < menuSize; i++) {
            MenuItem menuItem = mOptionMenu.getItem(i);
            if (menuItem.getItemId() == R.id.select_all) {
                menuItem.setVisible(true);
                menuItem.setTitle(R.string.select_all);
            } else {
                menuItem.setVisible(false);
            }
        }
    }

    private void invalidateViewInNormalMode() {
        mHeaderView.findViewById(R.id.checkbox).setVisibility(View.GONE);
        mBottomPanelView.setVisibility(View.GONE);
        mActivity.showNavigationBar();
        mThingInfoAdapter.setMultipleMode(false);

        int menuSize = mOptionMenu.size();
        for (int i = 0; i < menuSize; i++) {
            MenuItem menuItem = mOptionMenu.getItem(i);
            int id = menuItem.getItemId();
            if (id == R.id.select_all) {
                menuItem.setVisible(false);
            } else if (id == R.id.add_button) {
                menuItem.setVisible(!mInSearchMode);
            } else if (id == R.id.show_all) {
                menuItem.setVisible(mInSearchMode);
            } else {
                menuItem.setVisible(true);
            }
        }
    }

    private void updateSelectAllMenuHint(MenuItem menuItem) {
        if (mThingInfoAdapter.isAllSelected()) {
            menuItem.setTitle(R.string.select_none);
        } else {
            menuItem.setTitle(R.string.select_all);
        }
    }

    private void toggleShowAllState(boolean inSearchMode) {
        mInSearchMode = inSearchMode;
        invalidateViewInNormalMode();
        mOptionMenu.findItem(R.id.show_all).setVisible(mInSearchMode);
    }

    @Override
    public void onAddOrQuery(List<ThingInfo> ThingInfoList) {
        mHandler.post(() -> {
            // Object is sorted by default encoding, so we need to resort it by pinyin for Chinese
            if (mSortState.state != null && (ThingEditFields.Thing_NAME.equals(mSortState.field)
                    || ThingEditFields.Time.equals(mSortState.field) || ThingEditFields.LOCATION.equals(
                    mSortState.field))) {
                Collections.sort(ThingInfoList, (o1, o2) -> {
                    int result;
                    if (ThingEditFields.Thing_NAME.equals(mSortState.field)) {
                        result = o1.getThingName().compareTo(o2.getThingName());
                    } else if (ThingEditFields.Time.equals(mSortState.field)) {
                        result = o1.getTime().compareTo(o2.getTime());
                    } else {
                        result = o1.getLocation().compareTo(o2.getLocation());
                    }
                    if (mSortState.state == SortState.State.UP) {
                        return result;
                    } else {
                        return -result;
                    }
                });
            }
            mThingInfoAdapter.addThings(ThingInfoList);
        });
    }

    @Override
    public void onSubscribe(List<ThingInfo> ThingInfoList) {
        if (!mInSearchMode) {
            mHandler.post(() -> {
                if (ThingInfoList.isEmpty()) {
                    Toast.makeText(getContext(), R.string.empty_thing_list, Toast.LENGTH_SHORT).show();
                }
                mThingInfoAdapter.addThings(ThingInfoList);
            });
        }
    }

    @Override
    public void onDelete(List<ThingInfo> ThingInfoList) {
        mHandler.post(() -> mThingInfoAdapter.deleteThings(ThingInfoList));
    }

    @Override
    public void updateUiOnError(String errorMessage) {
        // dummy
    }

    private void updateSortState(String field, View view) {
        cleanSortState();

        mSortState.field = field;
        ImageView newDownArrowView = view.findViewById(R.id.arrow_down);
        ImageView newUpArrowView = view.findViewById(R.id.arrow_up);
        if (mSortState.state == SortState.State.UP) {
            mSortState.state = SortState.State.DOWN;
            newDownArrowView.setImageResource(R.drawable.arrow_down_selected);
        } else {
            newUpArrowView.setImageResource(R.drawable.arrow_up_selected);
            mSortState.state = SortState.State.UP;
        }
        mSortState.downArrowView = newDownArrowView;
        mSortState.upArrowView = newUpArrowView;
    }

    private void cleanSortState() {
        mSortState.field = null;
        if (mSortState.upArrowView != null) {
            mSortState.upArrowView.setImageResource(R.drawable.arrow_up);
        }
        if (mSortState.downArrowView != null) {
            mSortState.downArrowView.setImageResource(R.drawable.arrow_down);
        }
    }

    private void queryWithOrder() {
        invalidateViewInNormalMode();
        CloudDBZoneQuery<ThingInfo> query = CloudDBZoneQuery.where(ThingInfo.class);
        if (!mQueryInfo.thingName.isEmpty()) {
            query.contains(ThingEditFields.Thing_NAME, mQueryInfo.thingName);
        }
        if (mQueryInfo.showCount > 0) {
            query.limit(mQueryInfo.showCount);
        }
        if (mSortState.state == SortState.State.UP) {
            query.orderByAsc(mSortState.field);
        } else {
            query.orderByDesc(mSortState.field);
        }
        mHandler.post(() -> mCloudDBZoneWrapper.queryThings(query));
    }

    private static final class SortState {
        String field;

        ImageView upArrowView;

        ImageView downArrowView;

        State state;

        enum State {
            UP,
            DOWN
        }
    }

    private static class ThingInfoAdapter extends BaseAdapter {
        private final List<ThingInfo> mThingList = new ArrayList<>();

        private final SparseBooleanArray mCheckState = new SparseBooleanArray();

        private final LayoutInflater mInflater;

        private boolean mIsMultipleMode = false;

        ThingInfoAdapter(Context context) {
            mInflater = LayoutInflater.from(context);
        }

        void addThings(List<ThingInfo> ThingInfoList) {
            mThingList.clear();
            mThingList.addAll(ThingInfoList);
            notifyDataSetChanged();
        }

        void deleteThings(List<ThingInfo> ThingInfoList) {
            for (ThingInfo ThingInfo : ThingInfoList) {
                mThingList.remove(ThingInfo);
            }
            notifyDataSetChanged();
        }

        void check(int position) {
            if (mCheckState.get(position)) {
                mCheckState.delete(position);
            } else {
                mCheckState.put(position, true);
            }
            notifyDataSetChanged();
        }

        void onSelectAllMenuClicked() {
            // Current state is all elements selected, so switch the state to none selected
            if (mCheckState.size() == getCount()) {
                mCheckState.clear();
            } else {
                mCheckState.clear();
                for (int i = 0; i < getCount(); i++) {
                    mCheckState.put(i, true);
                }
            }
            notifyDataSetChanged();
        }

        boolean isAllSelected() {
            return mCheckState.size() == mThingList.size();
        }

        List<ThingInfo> getSelectedItems() {
            List<ThingInfo> ThingInfoList = new ArrayList<>();
            int selectCount = mCheckState.size();
            for (int i = 0; i < selectCount; i++) {
                ThingInfoList.add(mThingList.get(mCheckState.keyAt(i)));
            }
            return ThingInfoList;
        }

        boolean isMultipleMode() {
            return mIsMultipleMode;
        }

        void setMultipleMode(boolean isMultipleMode) {
            mIsMultipleMode = isMultipleMode;
            if (!isMultipleMode) {
                mCheckState.clear();
            }
            notifyDataSetChanged();
        }

        @Override
        public int getCount() {
            return mThingList.size();
        }

        @Override
        public Object getItem(int position) {
            return mThingList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder;
            if (convertView == null) {
                viewHolder = new ViewHolder();
                convertView = mInflater.inflate(R.layout.thing_list_item, null);
                viewHolder.thingNameView = convertView.findViewById(R.id.thing_name);
                viewHolder.timeView = convertView.findViewById(R.id.time);
                viewHolder.locationView = convertView.findViewById(R.id.location);
                viewHolder.phoneView = convertView.findViewById(R.id.phone);
                viewHolder.checkBox = convertView.findViewById(R.id.checkbox);
                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }
            ThingInfo ThingInfo = mThingList.get(position);
            viewHolder.thingNameView.setText(ThingInfo.getThingName());
            viewHolder.timeView.setText(DateUtils.formatDate(ThingInfo.getTime()));
            viewHolder.locationView.setText(ThingInfo.getLocation());
            viewHolder.phoneView.setText(ThingInfo.getPhone());
            if (mIsMultipleMode) {
                viewHolder.checkBox.setVisibility(View.VISIBLE);
            } else {
                viewHolder.checkBox.setVisibility(View.GONE);
            }
            viewHolder.checkBox.setChecked(mCheckState.get(position, false));
            return convertView;
        }
    }

    private static final class ViewHolder {
        CheckBox checkBox;

        TextView thingNameView;

        TextView timeView;

        TextView locationView;

        TextView phoneView;
    }

    private static final class QueryInfo {
        String thingName = "";

        double lowestPrice = 0.0;

        double highestPrice = 0.0;

        int showCount = 0;

        void clean() {
            thingName = "";
            lowestPrice = 0.0;
            highestPrice = 0.0;
            showCount = 0;
        }
    }
}
